package com.googlecode.pdfbricks.cli.parser;

import com.googlecode.pdfbricks.cli.constant.CommandConstant;
import com.googlecode.pdfbricks.engine.to.FilePageRange;
import com.googlecode.pdfbricks.engine.to.PageRange;

/**
 * @author Johny Huang
 * @date 2009-3-12
 */
public class FilePageRangeParser {
	
	private static final FilePageRangeParser PARSER=new FilePageRangeParser();

	private FilePageRangeParser(){
		
	}
	
	public static FilePageRangeParser getInstance(){
		return PARSER;
	}
	
	/**
	 * @param filePageRangeStr
	 * @return the object which contain the file path and the page indexes information.
	 * 
	 * The command string should have a patter like 'filePath','filePath<startPageIndex-endPageIndex>' or 'filePath<pageIndex1,pageIndex2>'.
	 * 
	 * For example:
	 *     command string: "file:/c:/test.pdf<1-6,9>"   
	 *     after parsed:
	 *     
	 *     FilePageRange{
	 *     filePath->file:/c:/test.pdf
	 *     pageRangeList->{PageRange{
	 *     					 startIndex->1,
	 *     					 endIndex->6
	 *     					},
	 *     					PageRange{
	 *     					 startIndex->9,
	 *     					 endIndex->9
	 *     					}}
	 *     }
	 *     
	 *  
	 */
	public FilePageRange parse(final String filePageRangeStr){
		if (filePageRangeStr == null) {
			throw new NullPointerException("incomplete command");
		}

		FilePageRange fpr = new FilePageRange();
		int stIndex = filePageRangeStr.indexOf(CommandConstant.LT);
		int ltIndex = filePageRangeStr.indexOf(CommandConstant.MT);

		if (ltIndex == -1 && stIndex == -1) {
			//If there is no '<' or '>' in command,it should be a single page number.
			fpr.setFilePath(filePageRangeStr);
			fpr.setAllPages(true);
			return fpr;
		}

		if (stIndex != -1 && ltIndex != -1) {
			//If both '<' and '>' exist, it should be a range of pages.
			fpr.setFilePath(filePageRangeStr.substring(0,stIndex));
			String pageStr=filePageRangeStr.substring(stIndex+1, ltIndex);
			String[] pageRangeStrs=pageStr.split(CommandConstant.COMMA);
			for(int i=0;i<pageRangeStrs.length;i++){
				fpr.addPageRange(parsePageRange(pageRangeStrs[i]));
			}			
		}else{
			throw new CommandParseException("Incomplete command:'<' and '>' must exist in pairs.");
		}

		return fpr;
	}
	
	private PageRange parsePageRange(String pageRangeStr){
		if(pageRangeStr==null){
			throw new NullPointerException("incomplete command");
		}
		
		PageRange pr=new PageRange();		
		int minusIndex=pageRangeStr.indexOf(CommandConstant.MINUS);
		
		if(minusIndex==-1){
			//If it's a single page.
			try{
			pr.setSinglePage(Integer.valueOf(pageRangeStr).intValue());
			}catch(NumberFormatException nfe){
				throw new CommandParseException("Invalid page numbers",nfe);
			}
		}else{		
			//If it's a range of pages.
			String[] indexes=pageRangeStr.split(CommandConstant.MINUS);
			if(indexes.length<2){
				throw new CommandParseException("Incomplete command:page range must be writen in '<startIndex-endIndex>' pattern.");
			}else{
				int startIndex,endIndex;
				
				try{
					startIndex=Integer.valueOf(indexes[0]).intValue();
					endIndex=Integer.valueOf(indexes[1]).intValue();
				}catch(NumberFormatException nfe){
					throw new CommandParseException("Invalid page numbers",nfe);
				}
				
				pr.setStartIndex(startIndex);
				pr.setEndIndex(endIndex);
				
			}
		}		
		
		return pr;
	}
}
